package com.mp.approvalreq.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.mp.approvalreq.entity.*;
import com.mp.approvalreq.entity.dto.ComponentGroupDTO;
import com.mp.approvalreq.entity.po.ComponentGroup;
import com.mp.approvalreq.entity.vo.Component;
import com.mp.approvalreq.service.ReadTemplateServicePrx;
import com.mp.approvalreq.service.RequestServicePrx;
import com.mp.approvalreq.service.SelectApprovalServicePrx;
import com.mp.user.entity.User;
import com.mp.user.service.UserServicePrx;
import com.plusmoney.exception.RpcServerLogicalException;
import com.plusmoney.util.Utils;
import com.qq.tars.client.util.ServantUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.NDC;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.*;

/**
 * 导出全公司某些天的审批
 */
public class ExportAllCompanyApproval extends ExportTemplate {

    private static final Logger logger = LoggerFactory.getLogger(ExportAllCompanyApproval.class);

    public ExportAllCompanyApproval(ExcelParam excelParam) {
        super(excelParam);
    }


    /**
     * 新版报销版本
     */
    private static HashMap<Integer, Request> newExpenseVersionMap = new HashMap();

    /**
     * 过滤掉重复的名字
     *
     * @param sheetNameList
     * @param name
     * @return
     */
    private static String shiftRepeatSheetName(List<String> sheetNameList, String name) {
        if (StringUtils.isEmpty(name)) {
            throw new RpcServerLogicalException(1, "审批名为空");
        }

        String sheetName;
        int count = 0;
        for (String previousName : sheetNameList) {
            if (previousName.equals(name)) {
                count++;
            }
        }
        sheetNameList.add(name);
        if (count == 0) {
            sheetName = name;
        } else {
            sheetName = name + "-" + (count + 1);
        }

        return sheetName;
    }


    public void createExcel() throws Throwable {
        if (excelParam.isExportMyApply()) {
            throw new RpcServerLogicalException("导出类型错误");
        }

        NDC.push("currentTimeMillis=" + System.currentTimeMillis());
        try {
            ReadTemplateServicePrx readTemplateServicePrx = excelParam.getReadService();
            RequestServicePrx requestServicePrx = ServantUtils.getObject(RequestServicePrx.class);
            User user = excelParam.getUser();
            List<User> userList = new ArrayList<User>();
            userList.add(user);
            List<Integer> templateIds = excelParam.getTemplateIds();
            List<String> days = excelParam.getDays();

            //  获取所有需要导出的 模板的详情
            List<Template> templateList = readTemplateServicePrx.getTemplateDetailByTemplateIdList(templateIds);

            //  得到该公司所有员工contactId:User(contactID,name,离职时间)
            UserServicePrx userServicePrx = ServantUtils.getObject(UserServicePrx.class);
            convertUserToPeople(userServicePrx.getAllUserBaseInfoList(user.getCompanyId()));

            //  导出审批类型：请假、外出、申购等等
            StringBuilder templateNames = new StringBuilder();

            HSSFWorkbook wb = new HSSFWorkbook();
            initCellStyle(wb);

            List<String> sheetNameList = new LinkedList<>();

            for (Template template : templateList) {
                String sheetName = template.getTemplateName();
                templateNames.append(sheetName).append("、");
                sheetName = CheckUtil.replaceNonlicetSheetNameCharacter(sheetName);     // 移除非法字符的的sheet名
                sheetName = shiftRepeatSheetName(sheetNameList, sheetName);             // 去重

                HSSFSheet sheet = wb.createSheet(sheetName);
                setNoGridLines(sheet);
                createExcelHeadByDay(sheet, sheetName);

                int lastHeaderRowIndex = sheet.getLastRowNum();           // 每个sheet的头部的最后一行(6)
                int itemStartIndex = lastHeaderRowIndex + 2;

                // 获取全公司在这些天申请过的审批模板
                List<Template> hasUsedTemplates = readTemplateServicePrx.getUsedTemplateInDaysByUser(template, days, userList, 0);
                if (ListHelper.isNullEmpty(hasUsedTemplates)) {
                    createExcelBodyByDays(sheet, null, itemStartIndex, template);
                } else {
                    for (Template usedTemp : hasUsedTemplates) {
                        List<Request> requests = requestServicePrx.getTemplateRequestByDateScope(usedTemp.getTemplateId(), days.get(0), days.get(1));

                        if (StringUtils.isEmpty(usedTemp.getComponentGroupJson())) {
                            recordNewExpenseVersionMap(requests);

                            try {
                                // 每个模板的打印不去影响其他打印
                                createExcelBodyByDays(sheet, requests, itemStartIndex, usedTemp);
                            } catch (Throwable e) {
                                logger.error(e.getMessage(), e);
                                MailUtils.sendMail(MailUtils.EMAIL, e.getMessage(), String.valueOf(usedTemp.getTemplateId()));
                            }
                        } else {
                            // 组件集
                            try {
                                SelectApprovalServicePrx selectApprovalService = ServantUtils.getObject(SelectApprovalServicePrx.class);
                                String componentGroupIds = ApprovalUtils.getComponentGroupIds(usedTemp.getComponentGroupJson());
                                List<ComponentGroupDTO> groupDTOs = selectApprovalService.getComponentGroupInfoDTOs(usedTemp.getCompanyId(), componentGroupIds);

                                List<ComponentGroup> groups = com.plusmoney.util.BeanUtils.dtos2pos(groupDTOs, ComponentGroup.class);
                                ApprovalUtils.setComponentGroupNum(usedTemp.getComponentGroupJson(), groups);

                                createExcelGroupBodyByDays(sheet, requests, itemStartIndex, usedTemp, groups);
                            } catch (Throwable e) {
                                logger.error(e.getMessage(), e);
                                MailUtils.sendMail(MailUtils.EMAIL, e.getMessage(), String.valueOf(usedTemp.getTemplateId()));
                                lineGroupIndexList.clear();
                            }
                        }

                        itemStartIndex = sheet.getLastRowNum() + 5;
                    }
                }

                // 合并头部
                mergeHeaderRegion(sheet, lastHeaderRowIndex);
                // 调整单元格内容宽度
                autoSizeOfSheetCell(sheet);
            }

            if (templateNames.toString().endsWith("、")) {
                templateNames.deleteCharAt(templateNames.length() - 1);
            }

            List<File> fileList = getFileList(wb, templateNames);
            String emailContent = getEmailContentByDays(templateNames.toString());
            sendEmail(emailContent, fileList);

        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw e;
        } finally {
            NDC.pop();
        }
    }

    private void recordNewExpenseVersionMap(List<Request> requests) {
        for (Request req : requests) {
            // 记录新版报销审批,需要合并
            if (req.getDefaultType() == Template.EXPENSES && req.getTotalMoney() != null) {
                newExpenseVersionMap.put(req.getRequestDkey(), req);
            }
        }
    }


    private void createExcelGroupBodyByDays(HSSFSheet sheet, List<Request> reqList, int startIndex, Template template, List<ComponentGroup> groups) throws Throwable {
        // 每次打印完一种sheet表后都要清空
        lineGroupIndexList.clear();
        groupIndexMap.clear();

        // 标题行内容: 申请时间、申请人、模板组件、参与人、审批人、默认抄送人、临时抄送人、归档人、批准时间

        int itemIndex = startIndex;                 // 开始行
        int startLineIndex = 1;                     // 开始列
        int lastLineIndex = 0;                      // 最后列

        // 排除掉组件集里面无需打印的子组件
        groups = shiftComponentGroup(groups);
        logger.info("该模板的groups:{}", groups.toString());

        for (int i = itemIndex; i <= itemIndex + 1; i++) {
            Row itemRow = ExcelUtil.createRow(sheet, i);
            if (i == itemIndex) {
                itemRow.setHeight((short) (69 * 20));
            }

            ExcelUtil.createCommonCell(itemRow, startLineIndex, headStyle, "编号");
            sheet.setColumnWidth(startLineIndex, 35 * 256);

            // 申请时间
            ExcelUtil.createCommonCell(itemRow, startLineIndex + 1, headStyle, "申请时间");
            sheet.setColumnWidth(startLineIndex + 1, 30 * 256);

            // 申请人
            applicantIndex = ExcelUtil.createCommonCell(itemRow, itemRow.getLastCellNum(), headStyle, "申请人").getColumnIndex();

            // 模板组件
            List<TemplateComponent> comList = getComponentList(template);
            // 排除一些不需要的组件
            shiftTemplateComponents(comList);

            if (i == itemIndex) {
                // 打印组件
                printGroupCom(comList, startLineIndex, itemRow, groups);
            } else {
                printSubComponent(comList, startLineIndex, itemRow, groups);
            }

            // 相关人群、审批数据
            relatePeopleIndex = ExcelUtil.createCommonCell(itemRow, itemRow.getLastCellNum(), headStyle, "参与人").getColumnIndex();
            statusIndex = ExcelUtil.createCommonCell(itemRow, itemRow.getLastCellNum(), headStyle, "审批状态").getColumnIndex();
            approverColIndex = ExcelUtil.createCommonCell(itemRow, itemRow.getLastCellNum(), headStyle, "审批人").getColumnIndex();
            ccColIndex = ExcelUtil.createCommonCell(itemRow, itemRow.getLastCellNum(), headStyle, "默认抄送人").getColumnIndex();
            ccTempColIndex = ExcelUtil.createCommonCell(itemRow, itemRow.getLastCellNum(), headStyle, "临时抄送人").getColumnIndex();
            archiveIndex = ExcelUtil.createCommonCell(itemRow, itemRow.getLastCellNum(), headStyle, "归档人").getColumnIndex();
            approvalTimeIndex = ExcelUtil.createCommonCell(itemRow, itemRow.getLastCellNum(), headStyle, "审批时间").getColumnIndex();
            commentIndex = ExcelUtil.createCommonCell(itemRow, itemRow.getLastCellNum(), headStyle, "审批评论").getColumnIndex();
            lastLineIndex = itemRow.getLastCellNum();
        }

        /*
         *  先合模板第一行中重复打印的组件集名称
         */
        for (LinkedList<Integer> groupColumnIndex : lineGroupIndexList) {
            if (groupColumnIndex.size() < 2) {
                continue;
            }
            logger.info("合并开始列:{}, 合并结束列:{}", groupColumnIndex.getFirst(), groupColumnIndex.getLast());
            ExcelUtil.createRegion(sheet, itemIndex, itemIndex, groupColumnIndex.getFirst(), groupColumnIndex.getLast());
        }

        logger.info("第一列:{}, 最后一列:{}", startLineIndex, lastLineIndex);
        /*
         *  再合并模板第一行和第二行除组件集的以外的列
         */
        for (int i = startLineIndex; i < lastLineIndex; i++) {
            boolean isMerge = true;
            for (LinkedList<Integer> groupColumnIndex : lineGroupIndexList) {
                if (groupColumnIndex.contains(i)) {
                    logger.info("该{}不需要合并", i);
                    isMerge = false;
                    break;
                }
            }
            // 上下合并
            if (isMerge) {
                logger.info("开始行:{}, 结束行:{}, 开始列:{}, 结束列:{}", itemIndex, itemIndex + 1, i, i);
                ExcelUtil.createRegion(sheet, itemIndex, itemIndex + 1, i, i);
            }
        }

        itemIndex += 1;
        if (ListHelper.isNotNullEmpty(reqList)) {
            // 打印审批组件内容
            printComponentGroupValue(sheet, reqList, itemIndex + 1, groups);
        }
    }


    private void createExcelBodyByDays(HSSFSheet sheet, List<Request> reqList, int startIndex, Template template)
     throws Throwable {
        // 标题行内容: 申请时间、申请人、模板组件、参与人、审批人、默认抄送人、临时抄送人、归档人、批准时间

        int startLineIndex = 1;                     // 开始列

        Row itemRow = ExcelUtil.createRow(sheet, startIndex);

        ExcelUtil.createCommonCell(itemRow, startLineIndex, headStyle, "编号");
        sheet.setColumnWidth(startLineIndex, 35 * 256);

        // 申请时间
        ExcelUtil.createCommonCell(itemRow, startLineIndex + 1, headStyle, "申请时间");
        sheet.setColumnWidth(startLineIndex + 1, 30 * 256);

        // 申请人
        applicantIndex = ExcelUtil.createCommonCell(itemRow, itemRow.getLastCellNum(), headStyle, "申请人").getColumnIndex();

        // 模板组件
        List<TemplateComponent> comList = getComponentList(template);
        // 排除一些不需要的组件
        shiftTemplateComponents(comList);
        // 打印组件
        createComponentInSheet(comList, startLineIndex, itemRow, null);

        if (template.getDefaultType() == Template.LEAVE) {
            leaveDurationIndex = ExcelUtil.createCommonCell(itemRow, itemRow.getLastCellNum(), headStyle, "请假时长").getColumnIndex();
        }
        // 相关人群、审批数据
        relatePeopleIndex = ExcelUtil.createCommonCell(itemRow, itemRow.getLastCellNum(), headStyle, "参与人").getColumnIndex();
        statusIndex = ExcelUtil.createCommonCell(itemRow, itemRow.getLastCellNum(), headStyle, "审批状态").getColumnIndex();
        approverColIndex = ExcelUtil.createCommonCell(itemRow, itemRow.getLastCellNum(), headStyle, "审批人").getColumnIndex();
        ccColIndex = ExcelUtil.createCommonCell(itemRow, itemRow.getLastCellNum(), headStyle, "默认抄送人").getColumnIndex();
        ccTempColIndex = ExcelUtil.createCommonCell(itemRow, itemRow.getLastCellNum(), headStyle, "临时抄送人").getColumnIndex();
        archiveIndex = ExcelUtil.createCommonCell(itemRow, itemRow.getLastCellNum(), headStyle, "归档人").getColumnIndex();
        approvalTimeIndex = ExcelUtil.createCommonCell(itemRow, itemRow.getLastCellNum(), headStyle, "审批时间").getColumnIndex();
        commentIndex = ExcelUtil.createCommonCell(itemRow, itemRow.getLastCellNum(), headStyle, "审批评论").getColumnIndex();

        if (ListHelper.isNotNullEmpty(reqList)) {
            // 打印审批组件内容
            printRequestContent(sheet, reqList, startIndex);
        }
    }

    private int applicantIndex;
    private int relatePeopleIndex;
    private int statusIndex;
    private int approverColIndex;
    private int ccColIndex;
    private int ccTempColIndex;
    private int archiveIndex;
    private int approvalTimeIndex;
    private int commentIndex;
    private int leaveDurationIndex;


    private void printComponentGroupValue(HSSFSheet sheet, List<Request> reqList, int headRowIndex, List<ComponentGroup> groups) throws Throwable {
        for (Request req : reqList) {
            headRowIndex += printRepeatGroupValue(sheet, req, headRowIndex, groups);
        }
    }

    static class SortValue {
        Integer sort;
        List<Component> components;

        public Integer getSort() {
            return sort;
        }

        public void setSort(Integer sort) {
            this.sort = sort;
        }

        public List<Component> getComponents() {
            return components;
        }

        public void setComponents(List<Component> components) {
            this.components = components;
        }

        @Override
        public String toString() {
            return "SortValue{" +
             "sort=" + sort +
             ", components=" + components +
             '}';
        }
    }

    /**
     * 组件集num, 组件集的值
     */
    private Map<Integer, List<SortValue>> sortMap = new HashMap<>();

    private void initSortMap(List<ComponentGroup> groups, List<TemplateComponent> componentList) {
        for (TemplateComponent component : componentList) {
            if (component.getType() == ContentType.COMPONENT_GROUP) {
                for (ComponentGroup group : groups) {
                    if (component.getNum().equals(group.getNum())) {
                        /**
                         * 组件集乜有填写时,前端不会传值, 这里要初始化一下
                         */
                        if (StringUtils.isEmpty(component.getValue())) {
                            List<SortValue> values = new ArrayList<>();
                            SortValue sortValue = new SortValue();
                            sortValue.setSort(1);
                            List<Component> components = new ArrayList<>();
                            for (Component component1 : group.getComponents()) {
                                components.add(initComponent(component1, ""));
                            }
                            sortValue.setComponents(components);
                            values.add(sortValue);
                            sortMap.put(component.getNum(), values);
                        } else {
                            sortMap.put(component.getNum(), setValue(component.getValue(), group.getComponents(), component.getNum()));
                        }
                    }
                }
            }
        }
    }


    private List<SortValue> setValue(String jsonValue, List<Component> components, int num) {
        List<SortValue> values = new ArrayList<>();

        JSONArray array = JSONArray.parseArray(jsonValue);
        for (int i = 0; i < array.size(); i++) {
            JSONObject object = array.getJSONObject(i);
            JSONArray valueArray = object.getJSONArray("value");
            Integer sort = object.getInteger("sort");

            logger.info("sort:{}, value:{}", sort, valueArray.toString());

            /**
             [{
             "sort":1,
             "value": [{"num":1, "value":"xx"},{"num":2, "value":""},{"num":3, "value":""}]
             },
             {
             "sort":2,
             "value": [{"num":1, "value":"xx"},{"num":2, "value":""},{"num":3, "value":""}]
             },
             {
             "sort":3,
             "value": [{"num":1, "value":"xx"},{"num":2, "value":"xx"},{"num":3, "value":"xx"}]
             }]
             */
            List<Component> list = new ArrayList<>(components.size());
            for (Component component : components) {
                for (int j = 0; j < valueArray.size(); j++) {
                    JSONObject valueObject = valueArray.getJSONObject(j);
                    if (valueObject.getInteger("num").equals(component.getNum())) {
                        list.add(initComponent(component, valueObject.getString("value")));
                    }
                }
            }
            SortValue sortValue = new SortValue();
            sortValue.setSort(sort);
            sortValue.setComponents(list);

            values.add(sortValue);
        }

        logger.info("num:{} || SortValue:{}", num, values);

        return values;
    }


    private Component initComponent(Component component, String value) {
        Component com = new Component();

        if (StringUtils.isEmpty(value)) {
            com.setValue(value);
        } else {
            if (component.getType() == ContentType.GROUP_LOCATION) {
                JSONObject jsonObject = JSON.parseObject(value);
                String location = jsonObject.getString("location");
                location = location == null ? "" : location;
                com.setValue(location);
            } else {
                com.setValue(value);
            }
        }

        com.setName(component.getName());
        com.setNeed(component.getNeed());
        com.setNum(component.getNum());
        com.setType(component.getType());

        return com;
    }


    private SortValue initEmptyValue(SortValue sortValue) {
        SortValue initValue = new SortValue();
        initValue.setSort(sortValue.getSort());

        List<Component> components = new ArrayList<>();
        for (Component component : sortValue.getComponents()) {
            Component com = new Component();

            com.setValue(component.getValue());
            com.setName(component.getName());
            com.setNeed(component.getNeed());
            com.setNum(component.getNum());
            com.setType(component.getType());

            if (StringUtils.isNotEmpty(com.getValue())) {
                com.setValue("/");
            }

            components.add(com);
        }

        initValue.setComponents(components);
        return initValue;
    }

    /**
     * 记录已打印的组件集num
     */
    private int printRepeatGroupValue(HSSFSheet sheet, Request req, int headRowIndex, List<ComponentGroup> groups) throws Throwable {

        // 组件集中提交最多的次数
        int sortCount = 1;
        List<TemplateComponent> componentList = JSONObject.parseArray(req.getTemplateComponent(), TemplateComponent.class);
        sortCount = getSortCount(sortCount, componentList);
        logger.info("组件集中提交最多的组件集次数:{}", sortCount);

        initSortMap(groups, componentList);

        int lastColumnIndex = 0;

        for (int i = 0; i < sortCount; i++) {
            int itemStartIndex = headRowIndex + i;
            Row itemRow = ExcelUtil.createRow(sheet, itemStartIndex);
            int approvalNumIndex = 1;                                       // 编号在第一列
            int applicantTimeLineIndex = 2;                                 // 申请时间在第二列

            // 编号
            ExcelUtil.createCommonCell(itemRow, approvalNumIndex, centerDataStyle, req.getApprovalNum());

            //  申请时间
            String createTime = changeCHTime(req.getCreateTime());
            ExcelUtil.createCommonCell(itemRow, applicantTimeLineIndex, centerDataStyle, createTime);
            sheet.setColumnWidth(applicantTimeLineIndex, 30 * 256);

            // 申请人
            printContent(req, itemRow, RequestFlag.APPLICANT);

            for (int num : numList) {
                for (TemplateComponent com : componentList) {
                    if (num != com.getNum()) {
                        continue;
                    }
                    int offset = numList.indexOf(num);
                    if (com.getType() == ContentType.COMPONENT_GROUP) {
                        offset = groupIndexMap.get(num);
                        logger.info("组件集子组件开始位置:{}", offset);

                        List<SortValue> sortValues = sortMap.get(num);
                        SortValue sortValue;
                        if (sortValues.size() <= i) {
                            sortValue = initEmptyValue(sortValues.get(0));
                        } else {
                            sortValue = sortValues.get(i);
                        }

                        List<Component> components = sortValue.getComponents();
                        for (int j = 0; j < components.size(); j++) {
                            int type = components.get(j).getType();
                            String value = components.get(j).getValue();
                            String name = components.get(j).getName();
                            logger.info("打印值:{}, 打印位置:{}, 列名:{}", value, offset + j, name);
                            if (type == MONEY_TYPE && StringUtils.isNotEmpty(value) && !value.equals("/")) {
                                ExcelUtil.createCommonCell(itemRow, offset + j, centerDataStyle, Double.valueOf(value));
                            } else {
                                ExcelUtil.createCommonCell(itemRow, offset + j, centerDataStyle, value);
                            }
                        }
                    } else {
                        String value = getValue(offset, com, req);
                        value = removeNewLine(value);
                        int index = itemRow.getLastCellNum();  // startLine + offset
                        logger.info("普通组件打印位置:{}, 打印值[{}], 列名:{}", index, value, com.getName());
                        if (isLeftDataStyle(offset)) {
                            ExcelUtil.createCommonCell(itemRow, index, leftDataStyle, value);
                        } else {
                            if (typeList.get(offset) == MONEY_TYPE && StringUtils.isNotEmpty(value)) {   // 如果是金额项
                                if (ExcelUtil.isJsonArrayStr(value)) {
                                    ExcelUtil.createCommonCell(itemRow, index, centerDataStyle, value);
                                } else {
                                    ExcelUtil.createCommonCell(itemRow, index, centerDataStyle, Double.valueOf(value));
                                }
                            } else {
                                ExcelUtil.createCommonCell(itemRow, index, centerDataStyle, value);
                            }
                        }
                    }
                }
            }

            // 相关人群、审批数据
            printContent(req, itemRow, RequestFlag.RELA_PEOPLE);
            printContent(req, itemRow, RequestFlag.APPROVAL_STATUS);
            printContent(req, itemRow, RequestFlag.JUDGER);
            printContent(req, itemRow, RequestFlag.CC);
            printContent(req, itemRow, RequestFlag.CC_TEMP);
            printContent(req, itemRow, RequestFlag.ARCHIVER);
            printContent(req, itemRow, RequestFlag.CONFIRM_TIME);
            printContent(req, itemRow, RequestFlag.COMMENT);

            lastColumnIndex = itemRow.getLastCellNum();
        }

        try {
            if (sortCount > 1) {
                for (int i = 1; i < lastColumnIndex; i++) {
                    boolean isMerge = true;
                    for (LinkedList<Integer> groupColumnIndex : lineGroupIndexList) {
                        if (groupColumnIndex.contains(i)) {
                            logger.info("该{}不需要合并", i);
                            isMerge = false;
                            break;
                        }
                    }
                    if (isMerge) {
                        logger.info("开始行:{}, 结束行:{}, 开始列:{}, 结束列:{}", headRowIndex, headRowIndex + sortCount - 1, i, i);
                        ExcelUtil.createRegion(sheet, headRowIndex, headRowIndex + sortCount - 1, i, i);
                    }
                }
            }
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
        }


        return sortCount;
    }


    private int getSortCount(int sortCount, List<TemplateComponent> componentList) {
        for (TemplateComponent component : componentList) {
            if (component.getType() == ContentType.COMPONENT_GROUP) {
                JSONArray arr = JSON.parseArray(component.getValue());
                if (Utils.isNotNull(arr) && arr.size() > sortCount) {
                    sortCount = arr.size();
                }
            }
        }
        return sortCount;
    }


    class ArrayFlag {
        int curr = 0;
        JSONArray array;

        public JSONObject getObject() {
            int i = curr;
            if (curr > array.size() - 1) {
                i = curr = 0;
            } else {
                curr++;
            }

            return array.getJSONObject(i);
        }

        public void setArray(JSONArray array) {
            this.array = array;
        }

        public JSONArray getArray() {
            return array;
        }
    }

    Map<Integer, ArrayFlag> flagMap = new HashMap<>();

    public JSONObject getObject(int sort, JSONArray array, int num) {
        ArrayFlag flag = flagMap.get(sort);
        if (Utils.isNull(flag)) {
            flag = new ArrayFlag();
            flag.setArray(array);
            flagMap.put(sort, flag);
        }

        JSONObject object = flag.getObject();
        if (object == null || array.isEmpty()) {
            return new JSONObject();
        }

        logger.info("本次取的子组件值:{}", object.toJSONString());

        int count = 0;
        List<Integer> subNums = subNumMap.get(num);
        while (!subNums.contains(object.getInteger("num"))) {
            object = flag.getObject();
            // 防止数据错误导致的死循环
            if (count > array.size() - 1) {
                break;
            }
            count++;
        }
        int index = subNums.indexOf(object.getInteger("num"));

        List<Integer> subTypes = subTypeMap.get(num);
        int type = subTypes.get(index);
        object.put("type", type);

        logger.info("该组件对应num:{}, 对应type:{}", num, type);

        return object;
    }


    private void printRequestContent(HSSFSheet sheet, List<Request> requestList, int headRowIndex) throws Throwable {
        for (int i = 0; i < requestList.size(); i++) {
            Request request = requestList.get(i);

            // 新版报销有多个报销明细,重复打印多行后进行合并
            if (newExpenseVersionMap.containsKey(request.getRequestDkey())) {
                try {
                    headRowIndex += printNewExpenseContent(sheet, request, headRowIndex);
                } catch (Throwable throwable) {
                    logger.error(throwable.getMessage(), throwable);
                    logger.error(JSONObject.toJSONString(request));
                    EmailUtils.sendMail("导出审批出错", request);
                }
                continue;
            }

            int itemStartIndex = headRowIndex + 1 + i;       // 标题行下一行,即内容开始行
            int approvalNumIndex = 1;                        // 编号第一列
            int applicantTimeLineIndex = 2;                  // 申请时间在第二列
            int applicantIndex = 3;                          // 申请人第三列
            int startLine = 4;                               // 内容开始列,隔开申请时间、申请人
            Row itemRow = ExcelUtil.createRow(sheet, itemStartIndex);

            // 审批编号
            ExcelUtil.createCommonCell(itemRow, approvalNumIndex, centerDataStyle, request.getApprovalNum());
            sheet.setColumnWidth(approvalNumIndex, 35 * 256);

            //  申请时间
            String createTime = changeCHTime(request.getCreateTime());
            ExcelUtil.createCommonCell(itemRow, applicantTimeLineIndex, centerDataStyle, createTime);
            sheet.setColumnWidth(applicantTimeLineIndex, 30 * 256);

            // 申请人
            printContent(request, itemRow, RequestFlag.APPLICANT);

            // 模板组件中对应的审批内容
            List<TemplateComponent> reqComponents = JSONObject.parseArray(request.getTemplateComponent(), TemplateComponent.class);
            for (int num : numList) {
                for (TemplateComponent reqCom : reqComponents) {
                    if (num != reqCom.getNum()) {
                        continue;
                    }
                    int offset = numList.indexOf(num);
                    String value = getValue(offset, reqCom, request);       // 获取组件的值
                    value = removeNewLine(value);
                    if (isLeftDataStyle(offset)) {
                        ExcelUtil.createCommonCell(itemRow, startLine + offset, leftDataStyle, value);
                    } else {
                        if (typeList.get(offset) == MONEY_TYPE && StringUtils.isNotEmpty(value)) {   // 如果是金额项
                            if (ExcelUtil.isJsonArrayStr(value)) {
                                ExcelUtil.createCommonCell(itemRow, startLine + offset, centerDataStyle, value);
                            } else {
                                // 设置成double类型,可以方便地让客户使用
                                ExcelUtil.createCommonCell(itemRow, startLine + offset, centerDataStyle, Double.valueOf(value));
                            }
                        } else {
                            ExcelUtil.createCommonCell(itemRow, startLine + offset, centerDataStyle, value);
                        }
                    }
                }
            }

            if (request.getDefaultType() == Template.LEAVE) {
                printContent(request, itemRow, RequestFlag.LEAVE_DURATION);
            }
            // 相关人群、审批数据
            printContent(request, itemRow, RequestFlag.RELA_PEOPLE);
            printContent(request, itemRow, RequestFlag.APPROVAL_STATUS);
            printContent(request, itemRow, RequestFlag.JUDGER);
            printContent(request, itemRow, RequestFlag.CC);
            printContent(request, itemRow, RequestFlag.CC_TEMP);
            printContent(request, itemRow, RequestFlag.ARCHIVER);
            printContent(request, itemRow, RequestFlag.CONFIRM_TIME);
            printContent(request, itemRow, RequestFlag.COMMENT);
        }
    }


    /**
     * 新版报销的重复打印,然后合并除了 报销事项、报销金额、报销支出以外的列
     *
     * @param sheet
     * @param req
     * @param headRowIndex
     * @return
     * @throws Throwable
     */
    private int printNewExpenseContent(HSSFSheet sheet, Request req, int headRowIndex) throws Throwable {
        List<TemplateComponent> reqComponents = JSONObject.parseArray(req.getTemplateComponent(), TemplateComponent.class);
        int valueCount = 0;         // 需要重复打印多少次
        for (int num : numList) {
            for (TemplateComponent reqCom : reqComponents) {
                if (!Objects.equals(reqCom.getNum(), num)) {
                    continue;
                }
                if (num == 1 || num == 2 || num == 3) {
                    JSONArray arr = JSONArray.parseArray(reqCom.getValue());
                    valueCount = arr.size();
                    break;
                }
            }
        }

        // 合并开始行、结束行
        int mergeStartLine = headRowIndex + 1;
        int mergeEndLine = headRowIndex + valueCount;

        for (int i = 0; i < valueCount; i++) {
            int itemStartIndex = headRowIndex + 1 + i;
            Row itemRow = ExcelUtil.createRow(sheet, itemStartIndex);
            int approvalNumIndex = 1;                                       // 编号在第一列
            int applicantTimeLineIndex = 2;                                 // 申请时间在第二列
            int applicantIndex = 3;                                         // 申请人第三列
            int startLine = 4;                                              // 组件内容第三列

            // 编号
            ExcelUtil.createCommonCell(itemRow, approvalNumIndex, centerDataStyle, req.getApprovalNum());

            //  申请时间
            String createTime = changeCHTime(req.getCreateTime());
            ExcelUtil.createCommonCell(itemRow, applicantTimeLineIndex, centerDataStyle, createTime);
            sheet.setColumnWidth(applicantTimeLineIndex, 30 * 256);

            // 申请人
            printContent(req, itemRow, RequestFlag.APPLICANT);

            for (int num : numList) {
                for (TemplateComponent reqCom : reqComponents) {
                    if (num != reqCom.getNum()) {
                        continue;
                    }

                    int offset = numList.indexOf(num);
                    String value = getValue(offset, reqCom, req);       // 获取组件的值
                    value = removeNewLine(value);

                    if (isLeftDataStyle(offset)) {
                        ExcelUtil.createCommonCell(itemRow, startLine + offset, leftDataStyle, value);

                    } else {
                        // 报销事项、金额、支出日期
                        if (num == 1 || num == 2 || num == 3) {
                            JSONArray arr = JSON.parseArray(value);
                            value = arr.getString(i);
                        }

                        if (typeList.get(offset) == MONEY_TYPE && StringUtils.isNotEmpty(value)) {   // 如果是金额项
                            ExcelUtil.createCommonCell(itemRow, startLine + offset, centerDataStyle, Double.valueOf(value));

                        } else {

                            ExcelUtil.createCommonCell(itemRow, startLine + offset, centerDataStyle, value);
                        }
                    }
                }
            }

            // 相关人群、审批数据
            printContent(req, itemRow, RequestFlag.RELA_PEOPLE);
            printContent(req, itemRow, RequestFlag.APPROVAL_STATUS);
            printContent(req, itemRow, RequestFlag.JUDGER);
            printContent(req, itemRow, RequestFlag.CC);
            printContent(req, itemRow, RequestFlag.CC_TEMP);
            printContent(req, itemRow, RequestFlag.ARCHIVER);
            printContent(req, itemRow, RequestFlag.CONFIRM_TIME);
            printContent(req, itemRow, RequestFlag.COMMENT);
        }

        if (valueCount > 1) {
            Row itemRow = sheet.getRow(sheet.getLastRowNum());
            for (int j = 1; j <= itemRow.getPhysicalNumberOfCells(); j++) {
                // 报销事项、金额、支出日期所在列无需打印
                if (j >= 4 && j <= 6) {
                    continue;
                }
                ExcelUtil.createRegion(sheet, mergeStartLine, mergeEndLine, j, j, 1, 1, 1, 1);
            }
        }

        return valueCount;
    }


    private void printContent(Request request, Row row, RequestFlag flag) throws Throwable {
        int index = getCellIndexByFlag(flag);
        CellStyle style = getCellStyle(flag);
        String content = getPrintContent(request, flag);
        if (StringUtils.isEmpty(content)) {
            ExcelUtil.createCommonCell(row, index, style, " ");
        } else {
            if (isPerson(flag)) {
                if (isApplicant(flag)) {
                    content = getApplicantName(content);
                } else {
                    content = getContactsName(content);
                }
            } else if (flag == RequestFlag.CONFIRM_TIME) {
                content = changeCHTimeV2(content);
            }
            ExcelUtil.createCommonCell(row, index, style, content);
        }
    }


    private CellStyle getCellStyle(RequestFlag flag) {
        CellStyle style;
        if (flag == RequestFlag.COMMENT) {
            style = leftDataStyle;
            // 审批评论左对齐
        } else {
            style = centerDataStyle;
        }
        return style;
    }

    private int getCellIndexByFlag(RequestFlag flag) {
        int index = 0;
        switch (flag) {
            case JUDGER:
                index = approverColIndex;
                break;
            case CC:
                index = ccColIndex;
                break;
            case CC_TEMP:
                index = ccTempColIndex;
                break;
            case RELA_PEOPLE:
                index = relatePeopleIndex;
                break;
            case APPROVAL_STATUS:
                index = statusIndex;
                break;
            case ARCHIVER:
                index = archiveIndex;
                break;
            case CONFIRM_TIME:
                index = approvalTimeIndex;
                break;
            case COMMENT:
                index = commentIndex;
                break;
            case APPLICANT:
                index = applicantIndex;
                break;
            case LEAVE_DURATION:
                index = leaveDurationIndex;
                break;
            default:
                break;
        }
        return index;
    }

    private String getValue(int offset, TemplateComponent reqCom, Request req) throws Throwable {
        StringBuilder value = new StringBuilder("");
        String comValue = reqCom.getValue();
        if (StringUtils.isEmpty(comValue)) {
            return value.toString();
        }

        switch (typeList.get(offset)) {
            case TIME_TYPE:
                value.append(changeCHTime(comValue));
                break;

            case SITE_TYPE:
                value.append(getSiteTypeValue(comValue));
                break;

            case CLIENT_TYPE:

            case ContentType.RELATE_SUPPLIER:
                value.append(getClientTypeValue(req.getRequestAncestorId()));
                break;

            // 如果是考勤方案,则截取最后一个数据字段, eg:美国考勤,2710; 截取为:美国考勤
            case ATTENDANCE_TYPE:
                if (comValue.contains(",")) {
                    value.append(comValue, 0, comValue.lastIndexOf(","));
                } else {
                    value.append(comValue);
                }
                break;

            case RECEIVE_CLOCK_TICK:
                value.append(getClockTick(comValue));
                break;

            case RECEIVE_CLOCK_TYPE:
                value.append(getClockTypeValue(comValue));
                break;

            case RECEIVE_CLOCK_TIME:
                value.append(getClockTime(comValue));
                break;

            case ContentType.DAYS_OFF_TOTAL_TIME:
                DaysOffTimeInfo daysOffTimeInfo = JSONObject.parseObject(comValue, DaysOffTimeInfo.class);
                value.append(daysOffTimeInfo.getTotalTime());
                break;

            default:
                value.append(comValue);
                break;
        }
        return value.toString();
    }


    private String getClockTime(String comValue) {
        JSONObject jsonObject = JSON.parseObject(comValue);
        return jsonObject.getString("scheduleWorkTime");
    }


    private String getClockTick(String comValue) {
        JSONObject jsonObject = JSON.parseObject(comValue);
        return jsonObject.getString("scheduleName");
    }


    private String getClockTypeValue(String comValue) {
        JSONObject jsonObject = JSON.parseObject(comValue);
        String value = "";
        switch (jsonObject.getString("signType")) {
            case "0":
                value = "签到";
                break;
            case "1":
                value = "签退";
                break;
            case "2":
                value = "上午签到";
                break;
            case "3":
                value = "上午签退";
                break;
            case "4":
                value = "下午签到";
                break;
            case "5":
                value = "下午签退";
                break;
            default:
                break;
        }

        return value;
    }

    /**
     * 用于合并
     */
    private List<LinkedList<Integer>> lineGroupIndexList = new LinkedList<LinkedList<Integer>>();


    // 打印模板组件
    private void createComponentInSheet(List<TemplateComponent> comList, int startLineIndex, Row itemRow, List<ComponentGroup> groups) {
        for (TemplateComponent component : comList) {
            int num = component.getNum();
            String name = component.getName();
            if (!numList.contains(num)) {           // 此组件无需打印
                continue;
            }
            int lineOffset = numList.indexOf(num);                          // 得到该组件在模板中的位置
            int lineIndex = startLineIndex + 3 + lineOffset;   // 开始列加一列（隔开编号、申请时间、申请人）再加上它的偏移量

            ExcelUtil.createCommonCell(itemRow, lineIndex, headStyle, name);        // 创建该组件
        }
    }

    /**
     * 每个组件集的开始位置
     */
    private Map<Integer, Integer> groupIndexMap = new HashMap<>();


    private void printGroupCom(List<TemplateComponent> comList, int startLineIndex, Row itemRow, List<ComponentGroup> groups)
     throws Throwable {
        // 已打印组件集中子组件的数量
        lastOffset = 0;
        for (TemplateComponent component : comList) {
            int num = component.getNum();
            String name = component.getName();
            int type = component.getType();
            if (!numList.contains(num)) {           // 此组件无需打印
                continue;
            }
            int lineOffset = numList.indexOf(num);                          // 得到该组件在模板中的位置
            int lineIndex = startLineIndex + 3 + lineOffset;                // 开始列加一列（隔开编号、申请时间、申请人）再加上它的偏移量

            logger.info("组件Num{} | name:{} | 所在列:{}, type:{}", num, name, lineIndex, type);

            // 如果是组件集,则有多少个子组件就打印多少列
            if (type == ContentType.COMPONENT_GROUP) {
                for (ComponentGroup group : groups) {
                    if (num == group.getNum()) {
                        // 记录每个组件集中子组件的开始列和结束列
                        LinkedList<Integer> groupColumnIndex = new LinkedList<>();

                        int leftIndex = lineIndex + lastOffset;
                        int rightIndex = leftIndex + group.getComponents().size();
                        lastOffset += group.getComponents().size() - 1;

                        logger.info("子组件开始列:{}, 子组件结束列:{}, 已打印组件集中子组件的数量:{}", leftIndex, rightIndex - 1, lastOffset);
                        for (int i = leftIndex; i < rightIndex; i++) {
                            ExcelUtil.createCommonCell(itemRow, i, headStyle, name);
                            groupColumnIndex.add(i);
                        }
                        lineGroupIndexList.add(groupColumnIndex);

                        groupIndexMap.put(num, leftIndex);
                    }
                }
            } else {
                ExcelUtil.createCommonCell(itemRow, lineIndex + lastOffset, headStyle, name);        // 创建该组件
            }
        }
    }


    private void printSubComponent(List<TemplateComponent> comList, int startLineIndex, Row itemRow, List<ComponentGroup> groups) {
        lastOffset = 0;
        for (TemplateComponent component : comList) {
            int num = component.getNum();
            String name = component.getName();
            int type = component.getType();
            if (!numList.contains(num)) {           // 此组件无需打印
                continue;
            }
            int lineOffset = numList.indexOf(num);                          // 得到该组件在模板中的位置
            int lineIndex = startLineIndex + 3 + lineOffset;                // 开始列加一列（隔开编号、申请时间、申请人）再加上它的偏移量
            logger.info("子组件Num{} | name:{} | lineIndex:{}, lineOffSet:{}", num, name, lineIndex, lineOffset);

            if (type == ContentType.COMPONENT_GROUP) {
                for (ComponentGroup group : groups) {
                    if (num == group.getNum()) {

                        int leftIndex = lineIndex + lastOffset;
                        int rightIndex = leftIndex + group.getComponents().size();
                        lastOffset += group.getComponents().size() - 1;

                        logger.info("leftIndex:{}, rightIndex:{}, lastOffset:{}", leftIndex, rightIndex, lastOffset);
                        int j = 0;
                        for (int i = leftIndex; i < rightIndex; i++) {
                            Component com = group.getComponents().get(j++);
                            // 打印每个子组件集
                            ExcelUtil.createCommonCell(itemRow, i, headStyle, com.getName());
                        }
                    }
                }
            } else {
                ExcelUtil.createCommonCell(itemRow, lineIndex + lastOffset, headStyle, name);        // 创建该组件
            }
        }
    }


    private void createExcelHeadByDay(HSSFSheet sheet, String templateName) throws Throwable {
        User user = excelParam.getUser();
        String sheetTime = getExportScopeStrByDays(excelParam.getDays());
        String exportTime = excelParam.getExportTime();
        try {
            int rowIndex = 1;
            Font titleFont = ExcelUtil.createFont(sheet.getWorkbook(), "微软雅黑", 26, false);
            CellStyle titleStyle = ExcelUtil.createCellStyle(sheet.getWorkbook(), 1, 1, 1, 1);
            titleStyle.setAlignment(HorizontalAlignment.LEFT);                                    // 左对齐
            titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);                            // 垂直居中
            titleStyle.setFont(titleFont);
            Row headerRow = sheet.createRow(rowIndex++);
            ExcelUtil.setHeight(headerRow, 3400);                                                // 固定标题行高3400
            ExcelUtil.createCommonCell(headerRow, 1, titleStyle, "大管加审批记录导出");                // 创建单元格参数：行,单元格所在列,该行样式,单元格内容      固定内容：大管加审批记录导出

            Font headerFont = ExcelUtil.createFont(sheet.getWorkbook(), "微软雅黑", 16, false);
            CellStyle headerStyle = ExcelUtil.createCellStyle(sheet.getWorkbook(), 1, 1, 1, 1, HorizontalAlignment.LEFT, VerticalAlignment.CENTER);
            headerStyle.setFont(headerFont);

            Row exportCompanyName = sheet.createRow(rowIndex++);
            ExcelUtil.setHeight(exportCompanyName, 2700);
            ExcelUtil.createCommonCell(exportCompanyName, 1, headerStyle, "公司名 :" + user.getCompanyName());

            Row exportApprovalType = sheet.createRow(rowIndex++);
            ExcelUtil.setHeight(exportApprovalType, 2700);
            ExcelUtil.createCommonCell(exportApprovalType, 1, headerStyle, "审批类型 :" + templateName);

            Row exportScopeRow = sheet.createRow(rowIndex++);
            ExcelUtil.setHeight(exportScopeRow, 2700);
            String exportScopeStr = "审批时间 :" + sheetTime;
            ExcelUtil.createCommonCell(exportScopeRow, 1, headerStyle, exportScopeStr);

            Row exportTimeRow = sheet.createRow(rowIndex++);
            ExcelUtil.setHeight(exportTimeRow, 2700);
            ExcelUtil.createCommonCell(exportTimeRow, 1, headerStyle, "导出时间 :" + exportTime);

            Row exportContactRow = sheet.createRow(rowIndex);
            ExcelUtil.setHeight(exportContactRow, 2700);
            ExcelUtil.createCommonCell(exportContactRow, 1, headerStyle, "导出人 :" + user.getContactName());
        } catch (Throwable e) {
            logger.error(e.getMessage(), e);
            throw e;
        }
    }


}
